package org.example.ssh.base

import com.alibaba.fastjson2.JSON
import net.schmizz.sshj.SSHClient
import java.nio.file.Files
import kotlin.io.path.Path

class SshConfig(
    var name: String,
    var desc: String = "",
    var sshHost: String = "192.168.180.146",
    var sshPort: Int = 22,
    var sshUsername: String = "root",
    var sshPassword: String = "123456",
    var sshKeyFile: String = "",
    var sshKeyPassphrase: String = "",
)

data class ContainerConfig(
    var name: String,
    var desc: String = "",
    var host: String,
    var sshCfg: SshConfig = SshConfig(""),
    var map: MutableMap<String, String> = mutableMapOf()
)

data class SshAndContainer(
    var hosts: MutableList<SshConfig>,
    var containers: MutableList<ContainerConfig>
)

data class SshCtx(
    var cfg: SshConfig,
    var cli: SSHClient,
    var cName: String,
)

var sshAndContainer = SshAndContainer(mutableListOf(), mutableListOf())
var sshMap = mutableMapOf<String, SSHClient>()
var sshCtxCliMap = mutableMapOf<String, SshCtx>()

class SSH {

    companion object {

        val isInit = false

        suspend fun exec(namePrefix: String, action: suspend (sshCtx: SshCtx) -> Unit) {
            initSshCfg()
            execF(getGroup(namePrefix), action)
        }

        suspend fun exec1(listStr: String, action: suspend (sshCtx: SshCtx) -> Unit) {
            initSshCfg()
            execF(getByList(listStr), action)
        }

        suspend fun exec1(list: List<String>, action: suspend (sshCtx: SshCtx) -> Unit) {
            initSshCfg()
            execF(list.map {
                sshCtxCliMap[it]!!
            }, action)
        }

        suspend fun execF(list: List<SshCtx>, action: suspend (sshCtx: SshCtx) -> Unit) {
            initSshCfg()
            val fails = mutableListOf<SshCtx>()
            list.forEach {
                try {
                    action(it)
                } catch (e: Exception) {
                    fails.add(it)
                    e.printStackTrace()
                }
            }
            val toList = fails.map { it.cfg.name }.toList()
            println("失败的服务器：${JSON.toJSONString(toList)}")
        }

        @JvmStatic
        fun initSshCfg(createCli: Boolean = true) {
            if(isInit) return
            sshAndContainer = JSON.parseObject(Files.readString(Path("./配置/sshConfig.json")), SshAndContainer::class.java)
            sshAndContainer.containers.forEach {
                it.sshCfg = sshAndContainer.hosts.find { cfg -> cfg.name == it.host }!!
            }

            if (createCli) {
                for (sshConfig in sshAndContainer.hosts) {
                    val ssh = SSHClient()
                    ssh.loadKnownHosts()
                    ssh.connect(sshConfig.sshHost, sshConfig.sshPort)
                    ssh.authPassword(sshConfig.sshUsername, sshConfig.sshPassword)
                    sshMap[sshConfig.name] = ssh
                }
                sshAndContainer.containers.forEach {
                    val ssh = sshMap[it.host]
                    val sshConfig = sshAndContainer.hosts.find { cfg -> cfg.name == it.host }!!
                    val sshCtx1 = SshCtx(sshConfig, ssh!!, it.name)
                    sshCtxCliMap.put(it.name, sshCtx1)
                }
            }
        }

        @JvmStatic
        fun getGroup(namePrefix: String): List<SshCtx> {
            if(!isInit) initSshCfg()
            return sshCtxCliMap.filter { it.key.startsWith(namePrefix) }.map { sshCtxCliMap[it.key]!! }.toList()
        }

        // 为一些失败的执行
        fun getByList(listStr: String): List<SshCtx> {
            val list = JSON.parseArray(listStr, String::class.java)
            return list.map {
                sshCtxCliMap[it]!!
            }
        }

        @JvmStatic
        fun getSsh(name: String): SshCtx {
            val ssh1 = sshCtxCliMap[name]
            return ssh1!!
        }

    }
}



